package com.dubbo.util;

import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ReferenceConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.rpc.service.GenericService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * 文件名称： DubboReferenceUtil<br/>
 * 初始作者： 【yax】 <br/>
 * 创建日期： 2019/7/2 17:45<br/>
 * 功能说明：  <br/>
 * <br/>
 * ================================================<br/>
 * 修改记录：<br/>
 * 修改作者 日期 修改内容<br/>
 * <br/>
 * ================================================<br/>
 * Copyright 中仑网络科技有限公司 2019/7/2 .All rights reserved.<br/>
 */
@Component
@Lazy
public class DubboReferenceUtil {

    private static final Logger LOG = Logger.getLogger("DubboReferenceUtil");

    //接口实例缓存
    private static Map<Class, Object> instanceCache = new ConcurrentHashMap<>();
    //接口实例缓存
    private static Map<String, GenericService> instanceStringCache = new ConcurrentHashMap<>();

    //接口引用缓存
    private static Map<Class,ReferenceConfig> referenceCache=new ConcurrentHashMap<>();
    //接口引用缓存
    private static Map<String,ReferenceConfig> referenceStringCache=new ConcurrentHashMap<>();

    //应用程序信息
    private ApplicationConfig application;

    //注册中心信息
    private RegistryConfig registry;

    private Boolean registryCheck;
    public static Integer registryTimeout;
    public static String directAddress;
    public static String zookeeperAddress;

    public  <T>T getDubboBeanByClass(Class<T> cla){
        return (T)instanceCache.computeIfAbsent(cla,k->getBean(k) );
    }
    public  GenericService getDubboBeanByString(String cla){
        return instanceStringCache.computeIfAbsent(cla,k->getBean(k) );
    }
    @PostConstruct
    private void init(){
        application = new ApplicationConfig();
        application.setName("dubbo-consumer-demo");

        // 连接注册中心配置
        registry = new RegistryConfig();
        registry.setAddress(zookeeperAddress);
        //registry.setProtocol(env.getProperty("dubbo.protocol"));

        registryCheck = false;
        registry.setCheck(registryCheck);
        registry.setTimeout(registryTimeout);
    }
    private  <T> T getBean(Class clazz) {
        // 注意：ReferenceConfig为重对象，内部封装了与注册中心的连接，以及与服务提供方的连接

        // 引用远程服务
        ReferenceConfig<T> reference = referenceCache.computeIfAbsent(clazz,k->{
            ReferenceConfig<T> refer = new ReferenceConfig<>(); // 此实例很重，封装了与注册中心的连接以及与提供者的连接，请自行缓存，否则可能造成内存和连接泄漏
            refer.setApplication(application);
            refer.setRegistry(registry); // 多个注册中心可以用setRegistries()
            refer.setInterface(clazz);
            if(directAddress!=null&&directAddress.length()>0) {
                refer.setUrl(directAddress + clazz.getName());
            }
            refer.setCheck(registryCheck);
            refer.setTimeout(registryTimeout);
            //reference.setVersion("1.0.0");
            return refer;
        });
        // 和本地bean一样使用xxxService
        Object instance = reference.get(); // 注意：此代理对象内部封装了所有通讯细节，对象较重，请缓存复用
        return (T) instance;
    }
    private   GenericService getBean(String className) {
        // 注意：ReferenceConfig为重对象，内部封装了与注册中心的连接，以及与服务提供方的连接

        // 引用远程服务
        ReferenceConfig<GenericService> reference = referenceStringCache.computeIfAbsent(className, k->{
            ReferenceConfig<GenericService> refer = new ReferenceConfig<>(); // 此实例很重，封装了与注册中心的连接以及与提供者的连接，请自行缓存，否则可能造成内存和连接泄漏
            refer.setApplication(application);
            refer.setRegistry(registry); // 多个注册中心可以用setRegistries()
            refer.setInterface(className);
            refer.setGeneric(true);
            if(directAddress!=null&&directAddress.length()>0) {
                refer.setUrl(directAddress + className);
            }
            if(className.contains("_directaddress_")){
                String name=className.split("_directaddress_")[1];
                String address=className.split("_directaddress_")[0];
                refer.setUrl(address +"/"+ name);
            }
            refer.setCheck(registryCheck);
            refer.setTimeout(registryTimeout);
            //reference.setVersion("1.0.0");
            return refer;
        });
        // 和本地bean一样使用xxxService
        GenericService instance = reference.get(); // 注意：此代理对象内部封装了所有通讯细节，对象较重，请缓存复用
        return instance;
    }
  public Object invokeMethod(String className,String methodName,Object params,boolean isParameter) throws Exception {
     // Class cla=Class.forName(className);
      //Object obj=getDubboBeanByString(className);
      //return cla.getMethod(methodName,Map.class).invoke(obj,params);
      GenericService genericService=getDubboBeanByString(className);
      if(!isParameter){
          return genericService.$invoke(methodName,null,null);
      }
      if(params==null||((Map)params).size()==0){
          return genericService.$invoke(methodName,new String[]{"java.util.Map"},new Object[]{new HashMap<>()});
      }
      return genericService.$invoke(methodName,new String[]{"java.util.Map"},new Object[]{params});
  }
}
